Frigör kraften i mikro-frontends med JavaScript Module Federation i Webpack 5. LÀr dig bygga skalbara, underhÄllbara och oberoende webbapplikationer.
JavaScript Module Federation med Webpack 5: En omfattande guide till mikro-frontends
I det stÀndigt förÀnderliga landskapet för webbutveckling kan det vara en skrÀmmande uppgift att bygga stora och komplexa applikationer. Traditionella monolitiska arkitekturer leder ofta till ökad utvecklingstid, flaskhalsar vid driftsÀttning och utmaningar med att upprÀtthÄlla kodkvaliteten. Mikro-frontends har framtrÀtt som ett kraftfullt arkitektoniskt mönster för att hantera dessa utmaningar, vilket gör att team kan bygga och driftsÀtta oberoende delar av en större webbapplikation. En av de mest lovande teknologierna för att implementera mikro-frontends Àr JavaScript Module Federation, introducerad i Webpack 5.
Vad Àr mikro-frontends?
Mikro-frontends Àr en arkitektonisk stil dÀr en frontend-applikation delas upp i mindre, oberoende enheter som kan utvecklas, testas och driftsÀttas autonomt av olika team. Varje mikro-frontend ansvarar för en specifik affÀrsdomÀn eller funktion, och de komponeras samman vid körtid för att bilda det kompletta anvÀndargrÀnssnittet.
TÀnk pÄ det som ett företag: istÀllet för att ha ett jÀttestort utvecklingsteam har du flera mindre team som fokuserar pÄ specifika omrÄden. Varje team kan arbeta sjÀlvstÀndigt, vilket möjliggör snabbare utvecklingscykler och enklare underhÄll. TÀnk pÄ en stor e-handelsplattform som Amazon; olika team kan hantera produktkatalogen, varukorgen, kassaprocessen och anvÀndarkontohanteringen. Dessa skulle alla kunna vara oberoende mikro-frontends.
Fördelar med mikro-frontends:
- Oberoende driftsÀttningar: Team kan driftsÀtta sina mikro-frontends oberoende, utan att pÄverka andra delar av applikationen. Detta minskar risken vid driftsÀttning och möjliggör snabbare releasecykler.
- Teknikagnostiskt: Olika mikro-frontends kan byggas med olika teknologier eller ramverk (t.ex. React, Angular, Vue.js). Detta gör att team kan vÀlja den bÀsta tekniken för sina specifika behov och gradvis anamma nya teknologier utan att behöva skriva om hela applikationen. TÀnk dig ett team som anvÀnder React för produktkatalogen, ett annat som anvÀnder Vue.js för marknadsföringssidor, och ett tredje som anvÀnder Angular för kassaprocessen.
- FörbÀttrad teamautonomi: Team har fullt Àgandeskap över sina mikro-frontends, vilket leder till ökad autonomi, snabbare beslutsfattande och förbÀttrad utvecklarproduktivitet.
- Ăkad skalbarhet: Mikro-frontends gör det möjligt att skala din applikation horisontellt genom att driftsĂ€tta enskilda mikro-frontends pĂ„ olika servrar.
- à teranvÀndbarhet av kod: Delade komponenter och bibliotek kan enkelt delas mellan mikro-frontends.
- LÀttare att underhÄlla: Mindre kodbaser Àr generellt lÀttare att förstÄ, underhÄlla och felsöka.
Utmaningar med mikro-frontends:
- Ăkad komplexitet: Att hantera flera mikro-frontends kan lĂ€gga till komplexitet i den övergripande arkitekturen, sĂ€rskilt nĂ€r det gĂ€ller kommunikation, state-hantering och driftsĂ€ttning.
- Prestanda-overhead: Att ladda flera mikro-frontends kan introducera prestanda-overhead, sÀrskilt om de inte Àr korrekt optimerade.
- GenomgÄende ansvarsomrÄden (Cross-Cutting Concerns): Att hantera genomgÄende ansvarsomrÄden som autentisering, auktorisering och temahantering kan vara utmanande i en mikro-frontend-arkitektur.
- DriftmÀssig overhead: KrÀver mogna DevOps-praxis och infrastruktur för att hantera driftsÀttning och övervakning av flera mikro-frontends.
Vad Àr JavaScript Module Federation?
JavaScript Module Federation Àr en funktion i Webpack 5 som lÄter dig dela kod mellan separat kompilerade JavaScript-applikationer vid körtid. Det gör det möjligt att exponera delar av din applikation som "moduler" som kan konsumeras av andra applikationer, utan att behöva publicera till ett centralt arkiv som npm.
TÀnk pÄ Module Federation som ett sÀtt att skapa ett federerat ekosystem av applikationer, dÀr varje applikation kan bidra med sin egen funktionalitet och konsumera funktionalitet frÄn andra applikationer. Detta eliminerar behovet av beroenden vid byggtid och möjliggör verkligt oberoende driftsÀttningar.
Till exempel kan ett team för ett designsystem exponera UI-komponenter som moduler, och olika applikationsteam kan konsumera dessa komponenter direkt frÄn designsystemets applikation, utan att behöva installera dem som npm-paket. NÀr designsystemteamet uppdaterar komponenterna, reflekteras Àndringarna automatiskt i alla konsumerande applikationer.
Nyckelkoncept i Module Federation:
- Host: Huvudapplikationen som konsumerar fjÀrrmoduler.
- Remote: En applikation som exponerar moduler för att konsumeras av andra applikationer.
- Shared Modules (Delade moduler): Moduler som delas mellan host- och remote-applikationer (t.ex. React, Lodash). Module Federation kan automatiskt hantera versionering och deduplicering av delade moduler för att sÀkerstÀlla att endast en version av varje modul laddas.
- Exposed Modules (Exponerade moduler): Specifika moduler frÄn en remote-applikation som görs tillgÀngliga för konsumtion av andra applikationer.
- RemoteEntry.js: En fil genererad av Webpack som innehÄller metadata om de exponerade modulerna i en remote-applikation. Host-applikationen anvÀnder denna fil för att upptÀcka och ladda fjÀrrmodulerna.
Konfigurera Module Federation med Webpack 5: En praktisk guide
LÄt oss gÄ igenom ett praktiskt exempel pÄ hur man konfigurerar Module Federation med Webpack 5. Vi skapar tvÄ enkla applikationer: en Host-applikation och en Remote-applikation. Remote-applikationen kommer att exponera en komponent, och Host-applikationen kommer att konsumera den.
1. Projektkonfiguration
Skapa tvÄ separata kataloger för dina applikationer: `host` och `remote`.
```bash mkdir host remote cd host npm init -y npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev npm install react react-dom cd ../remote npm init -y npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev npm install react react-dom ```2. Konfiguration av Remote-applikationen
I `remote`-katalogen, skapa följande filer:
- `src/index.js`: Startpunkt för applikationen.
- `src/RemoteComponent.jsx`: Komponenten som kommer att exponeras.
- `webpack.config.js`: Webpack-konfigurationsfil.
src/index.js:
```javascript import React from 'react'; import ReactDOM from 'react-dom/client'; import RemoteComponent from './RemoteComponent'; const App = () => (Remote Application
src/RemoteComponent.jsx:
```javascript import React from 'react'; const RemoteComponent = () => (This is a Remote Component!
Rendered from the Remote Application.
webpack.config.js:
```javascript const HtmlWebpackPlugin = require('html-webpack-plugin'); const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); const path = require('path'); module.exports = { entry: './src/index', mode: 'development', devServer: { port: 3001, static: { directory: path.join(__dirname, 'dist'), }, }, output: { publicPath: 'auto', }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-react', '@babel/preset-env'], }, }, }, ], }, plugins: [ new ModuleFederationPlugin({ name: 'remote', filename: 'remoteEntry.js', exposes: { './RemoteComponent': './src/RemoteComponent', }, shared: { react: { singleton: true, eager: true }, 'react-dom': { singleton: true, eager: true }, }, }), new HtmlWebpackPlugin({ template: './public/index.html', }), ], resolve: { extensions: ['.js', '.jsx'], }, }; ```Skapa `public/index.html` med grundlÀggande HTML-struktur. Det viktiga Àr `
`3. Konfiguration av Host-applikationen
I `host`-katalogen, skapa följande filer:
- `src/index.js`: Startpunkt för applikationen.
- `webpack.config.js`: Webpack-konfigurationsfil.
src/index.js:
```javascript import React, { Suspense } from 'react'; import ReactDOM from 'react-dom/client'; const RemoteComponent = React.lazy(() => import('remote/RemoteComponent')); const App = () => (Host Application
webpack.config.js:
```javascript const HtmlWebpackPlugin = require('html-webpack-plugin'); const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); const path = require('path'); module.exports = { entry: './src/index', mode: 'development', devServer: { port: 3000, static: { directory: path.join(__dirname, 'dist'), }, }, output: { publicPath: 'auto', }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-react', '@babel/preset-env'], }, }, }, ], }, plugins: [ new ModuleFederationPlugin({ name: 'host', remotes: { remote: 'remote@http://localhost:3001/remoteEntry.js', }, shared: { react: { singleton: true, eager: true }, 'react-dom': { singleton: true, eager: true }, }, }), new HtmlWebpackPlugin({ template: './public/index.html', }), ], resolve: { extensions: ['.js', '.jsx'], }, }; ```Skapa `public/index.html` med grundlÀggande HTML-struktur (liknande remote-appen). Det viktiga Àr `
`4. Installera Babel
Installera Babel-beroenden i bÄde `host`- och `remote`-katalogerna:
```bash npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader ```5. Kör applikationerna
LÀgg till följande skript i `package.json` i bÄde `host`- och `remote`-katalogerna:
```json "scripts": { "start": "webpack serve" } ```Starta nu bÄda applikationerna:
```bash cd remote npm start cd ../host npm start ```Ăppna din webblĂ€sare och navigera till `http://localhost:3000`. Du bör se Host-applikationen med Remote-komponenten renderad inuti den.
Förklaring av viktiga konfigurationsalternativ:
- `name`: Ett unikt namn för applikationen.
- `filename`: Namnet pÄ filen som kommer att innehÄlla metadata om de exponerade modulerna (t.ex. `remoteEntry.js`).
- `exposes`: En mappning av modulnamn till filsökvÀgar som specificerar vilka moduler som ska exponeras.
- `remotes`: En mappning av remote-applikationsnamn till URL:er som specificerar var man hittar remoteEntry.js-filen för varje remote-applikation.
- `shared`: En lista över moduler som ska delas mellan host- och remote-applikationerna. Alternativet `singleton: true` sÀkerstÀller att endast en instans av varje delad modul laddas. Alternativet `eager: true` sÀkerstÀller att den delade modulen laddas ivrigt (dvs. före nÄgra andra moduler).
Avancerade tekniker med Module Federation
Module Federation erbjuder mÄnga avancerade funktioner som kan hjÀlpa dig att bygga Ànnu mer sofistikerade mikro-frontend-arkitekturer.
Dynamiska Remotes
IstÀllet för att hÄrdkoda URL:erna till remote-applikationer i Webpack-konfigurationen kan du ladda dem dynamiskt vid körtid. Detta gör att du enkelt kan uppdatera platsen för remote-applikationer utan att behöva bygga om host-applikationen.
Du kan till exempel lagra URL:erna till remote-applikationer i en konfigurationsfil eller en databas och ladda dem dynamiskt med JavaScript.
```javascript // I webpack.config.js remotes: { remote: `promise new Promise(resolve => { const urlParams = new URLSearchParams(window.location.search); const remoteUrl = urlParams.get('remote'); // Anta att remoteUrl Àr nÄgot i stil med 'http://localhost:3001/remoteEntry.js' const script = document.createElement('script'); script.src = remoteUrl; script.onload = () => { // nyckeln till module federation Àr att remote-appen Àr // tillgÀnglig via namnet i remote-konfigurationen resolve(window.remote); }; document.head.appendChild(script); })`, }, ```Nu kan du ladda host-appen med en query-parameter `?remote=http://localhost:3001/remoteEntry.js`
Versionerade delade moduler
Module Federation kan automatiskt hantera versionering och deduplicering av delade moduler för att sÀkerstÀlla att endast en kompatibel version av varje modul laddas. Detta Àr sÀrskilt viktigt nÀr man hanterar stora och komplexa applikationer med mÄnga beroenden.
Du kan specificera versionsintervallet för varje delad modul i Webpack-konfigurationen.
```javascript // I webpack.config.js shared: { react: { singleton: true, eager: true, requiredVersion: '^18.0.0' }, 'react-dom': { singleton: true, eager: true, requiredVersion: '^18.0.0' }, }, ```Anpassade modulladdare
Module Federation lÄter dig definiera anpassade modulladdare som kan anvÀndas för att ladda moduler frÄn olika kÀllor eller i olika format. Detta kan vara anvÀndbart för att ladda moduler frÄn en CDN eller frÄn ett anpassat modulregister.
Dela state mellan mikro-frontends
En av utmaningarna med mikro-frontend-arkitekturer Àr att dela state mellan olika mikro-frontends. Det finns flera tillvÀgagÄngssÀtt du kan anvÀnda för att hantera denna utmaning:
- URL-baserad state-hantering: Lagra state i URL:en och anvÀnd URL:en för att kommunicera mellan mikro-frontends. Detta Àr ett enkelt och rakt tillvÀgagÄngssÀtt, men det kan bli omstÀndligt för komplext state.
- Anpassade hÀndelser (custom events): AnvÀnd anpassade hÀndelser för att sÀnda state-förÀndringar mellan mikro-frontends. Detta möjliggör lös koppling mellan mikro-frontends, men det kan vara svÄrt att hantera hÀndelseprenumerationer.
- Delat state-hanteringsbibliotek: AnvÀnd ett delat state-hanteringsbibliotek som Redux eller MobX för att hantera state för hela applikationen. Detta ger ett centraliserat och konsekvent sÀtt att hantera state, men det kan introducera ett beroende till ett specifikt state-hanteringsbibliotek.
- Message Broker: AnvÀnd en meddelandekö som RabbitMQ eller Kafka för att underlÀtta kommunikation och delning av state mellan mikro-frontends. Detta Àr en mer komplex lösning, men den erbjuder en hög grad av flexibilitet och skalbarhet.
BÀsta praxis för att implementera mikro-frontends med Module Federation
HÀr Àr nÄgra bÀsta praxis att tÀnka pÄ nÀr du implementerar mikro-frontends med Module Federation:
- Definiera tydliga grÀnser för varje mikro-frontend: Varje mikro-frontend bör ansvara för en specifik affÀrsdomÀn eller funktion och ha vÀldefinierade grÀnssnitt.
- AnvĂ€nd en konsekvent teknikstack: Ăven om Module Federation lĂ„ter dig anvĂ€nda olika teknologier för olika mikro-frontends, Ă€r det generellt en bra idĂ© att anvĂ€nda en konsekvent teknikstack för att minska komplexiteten och förbĂ€ttra underhĂ„llbarheten.
- Etablera tydliga kommunikationsprotokoll: Definiera tydliga kommunikationsprotokoll för hur mikro-frontends ska interagera med varandra.
- Automatisera driftsĂ€ttningsprocessen: Automatisera driftsĂ€ttningsprocessen för att sĂ€kerstĂ€lla att mikro-frontends kan driftsĂ€ttas oberoende och pĂ„litligt. ĂvervĂ€g att anvĂ€nda CI/CD-pipelines och verktyg för infrastruktur-som-kod.
- Ăvervaka prestandan för dina mikro-frontends: Ăvervaka prestandan för dina mikro-frontends för att identifiera och Ă„tgĂ€rda eventuella prestandaflaskhalsar. AnvĂ€nd verktyg som Google Analytics, New Relic eller Datadog.
- Implementera robust felhantering: Implementera robust felhantering för att sÀkerstÀlla att din applikation Àr motstÄndskraftig mot fel.
- Omfamna en decentraliserad styrmodell: Ge team befogenhet att fatta beslut om sina egna mikro-frontends, samtidigt som övergripande konsistens och kvalitet bibehÄlls.
Verkliga exempel pÄ Module Federation i praktiken
Ăven om specifika fallstudier ofta Ă€r konfidentiella, Ă€r hĂ€r nĂ„gra generaliserade scenarier dĂ€r Module Federation kan vara otroligt anvĂ€ndbart:
- E-handelsplattformar: Som nÀmnts tidigare kan stora e-handelsplattformar anvÀnda Module Federation för att bygga oberoende mikro-frontends för produktkatalogen, varukorgen, kassaprocessen och anvÀndarkontohanteringen. Detta gör att olika team kan arbeta pÄ dessa funktioner oberoende och driftsÀtta dem utan att pÄverka andra delar av applikationen. En global plattform kan anpassa funktioner för olika regioner via fjÀrrmoduler.
- Finansiella tjÀnsteapplikationer: Applikationer för finansiella tjÀnster har ofta komplexa anvÀndargrÀnssnitt med mÄnga olika funktioner. Module Federation kan anvÀndas för att bygga oberoende mikro-frontends för olika kontotyper, handelsplattformar och rapportpaneler. Efterlevnadsfunktioner som Àr unika för vissa lÀnder kan levereras via Module Federation.
- SjukvÄrdsportaler: SjukvÄrdsportaler kan anvÀnda Module Federation för att bygga oberoende mikro-frontends för patienthantering, tidsbokning och tillgÄng till medicinska journaler. Olika moduler för olika försÀkringsleverantörer eller regioner kan laddas dynamiskt.
- Content Management Systems (CMS): Ett CMS kan anvÀnda Module Federation för att lÄta anvÀndare lÀgga till anpassad funktionalitet pÄ sina webbplatser genom att ladda fjÀrrmoduler frÄn tredjepartsutvecklare. Olika teman, plugins och widgets kan distribueras som oberoende mikro-frontends.
- Learning Management Systems (LMS): Ett LMS kan erbjuda kurser som utvecklats oberoende och integreras i en enhetlig plattform via Module Federation. Uppdateringar av enskilda kurser krÀver inte om-driftsÀttning av hela plattformen.
Slutsats
JavaScript Module Federation i Webpack 5 erbjuder ett kraftfullt och flexibelt sÀtt att bygga mikro-frontend-arkitekturer. Det lÄter dig dela kod mellan separat kompilerade JavaScript-applikationer vid körtid, vilket möjliggör oberoende driftsÀttningar, teknisk mÄngfald och förbÀttrad teamautonomi. Genom att följa de bÀsta praxis som beskrivs i denna guide kan du utnyttja Module Federation för att bygga skalbara, underhÄllbara och innovativa webbapplikationer.
Framtiden för frontend-utveckling lutar utan tvekan mot modulÀra och distribuerade arkitekturer. Module Federation utgör ett avgörande verktyg för att bygga dessa moderna system, vilket gör det möjligt för team att skapa komplexa applikationer med större hastighet, flexibilitet och motstÄndskraft. Allt eftersom tekniken mognar kan vi förvÀnta oss att se Ànnu fler innovativa anvÀndningsfall och bÀsta praxis dyka upp.